package com.wu.controller;


import com.alibaba.dubbo.config.annotation.Reference;
import com.google.code.kaptcha.Producer;
import com.wu.pojo.dto.RegisterDTO;
import com.wu.pojo.po.orgPo.DataBak;
import com.wu.pojo.po.orgPo.OrgBase;
import com.wu.pojo.res.Result;
import com.wu.pojo.dto.UserInfoDTO;
import com.wu.service.DataBakService;
import com.wu.service.OrgBaseService;
import com.wu.utils.CommonUtils;
import com.wu.pojo.po.userPo.User;
import com.wu.service.UserService;
import com.wu.utils.FuzzyUtil;
import com.wu.utils.JwtUtils;
import com.wu.utils.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.UnsupportedEncodingException;
import java.util.*;

import static com.wu.constants.Constants.*;

/**
 * [用户登录相关功能接口]
 *
 * @Author : [wuzhengru]
 * @Version : [v1.0]
 * @Date : [2021/3/11 02:34]
 */
@RestController
@RequestMapping("/api/v1/user")
@Slf4j
@Api(tags = "用户登录相关功能接口", description = "UserController")
public class UserController {
    @Reference
    private OrgBaseService orgBaseService;
    @Reference
    private UserService userService;
    @Reference
    private DataBakService dataBakService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private Producer captchaProducer = null;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    JavaMailSenderImpl javaMailSender;

    @ApiOperation("生成图形验证码")
    @RequestMapping("/kaptcha")
    public void getKaptchaImage(HttpServletResponse response) throws Exception {

        // 1、设置resp
        response.setContentType("image/jpeg");

        // 2、生成验证码
        String capText = captchaProducer.createText();

        // 3、放入redis，过期时间60s
        String authCodeKey = CommonUtils.getUUID();
        redisUtil.set(AUTH_CODE.concat(authCodeKey), capText, 60);

        // 设置响应头信息，Access-Control-Expose-Headers是重点！
        response.setHeader("Access-Control-Expose-Headers", "auth-code");
        response.setHeader("auth-code", authCodeKey);

        // 4、向客户端写出图片
        BufferedImage bi = captchaProducer.createImage(capText);
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(bi, "jpg", out);
        try {
            out.flush();
        } finally {
            out.close();
        }
    }

    @ApiOperation("用户信息登录验证")
    @PostMapping("userInfoValid")
    public Result userInfoValid(@Valid @RequestBody UserInfoDTO userInfoDTO
            , BindingResult result, HttpServletResponse response, HttpServletRequest request) {

        // 1、参数校验
        Result res = Commonts.getErrors(result);
        if (!(null == res || "".equals(res))) {
            //return校验错误
            return Commonts.getErrors(result);
        }

        if (null == userInfoDTO.getAuthCodeKey()) {
            log.error("验证码uuid获取失败");
            return Result.fail("信息缺失，请刷新再试");
        }

        // 2、验证码校验
        if (null == redisUtil.get(AUTH_CODE.concat(userInfoDTO.getAuthCodeKey()))) { // redis拿到验证
            return Result.fail("验证码已失效！");
        }

        if (!((String) redisUtil.get(AUTH_CODE.concat(userInfoDTO.getAuthCodeKey()))).equalsIgnoreCase(userInfoDTO.getAuthCode())) { //忽略大小写
            return Result.fail("验证码错误！");
        }

        // 验证通过之后删除对应的key
        redisUtil.del(AUTH_CODE.concat(userInfoDTO.getAuthCodeKey()));

        // 3、账号密码校验
        String username = userInfoDTO.getUsername();
        String password = null;
        try {  //加密
            password = CommonUtils.encodeByMd5(userInfoDTO.getPassword());
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("密码加密错误", e);
        }

        // 验证账号
        if (null == userService.selectOne(new User().setUsername(username))) {
            return Result.fail("用户不存在，请核对账号信息！");
        }

        // 验证密码
        if (null == userService.selectOne(new User().setUsername(username).setPassword(password))) {
            return Result.fail("密码错误，请输入正确的密码！");
        }
        User user = userService.selectOne(new User().setUsername(username));
        // 判断用户状态
        if (!(user.getStatus() == 1)) {
            return Result.fail("该用户尚未激活！");
        }

        // 4、生成TOKEN
        String token = jwtUtils.generateToken(user);
        response.setHeader("Authorization", token);
        // 设置长时间不登录过期时间
        redisUtil.set(TOKEN.concat(token), token, 18000);

        JSONObject json = new JSONObject();
        json.put("username", username);
        json.put("Authorization", token);

        return Result.succ("用户信息校验成功！", json);
    }

    @RequiresRoles("admin")
    @RequiresAuthentication
    @ApiOperation("admin角色登录授权")
    @GetMapping("adminAuthorization")
    public Result admin() {
        return Result.succ("role-admin授权成功");
    }

    @RequiresRoles("user")
    @RequiresAuthentication
    @ApiOperation("user角色登录授权")
    @GetMapping("userAuthorization")
    public Result user() {
        return Result.succ("role-user授权成功");
    }

    @ApiOperation("生成动态验证码 ")
    @GetMapping("/setEmailCode")
    public Result setEmailCode() {

        // 1、生成验证码
        String mail = "892120027@qq.com";// 测试数据
        Random random = new Random();
        int number = random.nextInt(10000) + 1000;// 设置随机数验证码
        redisUtil.set(EMAIL_CODE, number + "", 60);// 存入redis

        // 2、发送
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setSubject("验证码通知");
        simpleMailMessage.setText("您本次操作验证码为：" + number);
        simpleMailMessage.setTo(mail);
        simpleMailMessage.setFrom("892120027@qq.com");
        javaMailSender.send(simpleMailMessage);

        return Result.succ("验证码已发送");
    }

    @ApiOperation("动态码验证")
    @GetMapping("SMSValid")
    public Result SMSValid(@RequestParam String checkCode) {

        // 1、比对验证码
        if (null == redisUtil.get(EMAIL_CODE)) { // redis拿到验证
            return Result.fail("验证码已失效！");
        }
        if (!(redisUtil.get(EMAIL_CODE)).equals(checkCode)) {
            return Result.fail("验证码错误！");
        }

        // 2、验证通过
        redisUtil.del(EMAIL_CODE);// 验证成功，删除验证码

        return Result.succ("验证码正确！");
    }

    @RequiresRoles("user")
    @ApiOperation("获取用户信息 ")
    @GetMapping("getUserInfo")
    public Result getUserInfo(@RequestParam String token) {

        // 参数校验
        if (token == null || "".equals(token)) {
            Result.fail("token为空");
        }
        // 解析token
        String userId = null;
        try {
            userId = (String)JwtUtils.getClaimByToken(token).get("userId");
        } catch (Exception e) {
            log.debug("token信息失效,userId提取失败",e);
            return Result.fail("token信息失效，请重新登录！");
        }
        // 查询
        User user = userService.selectOne(new User().setId(userId));
        OrgBase orgBase = orgBaseService.queryOrgByUserId(userId);
        // 脱敏处理
        String mobile = FuzzyUtil.cardFuzzy(user.getMobile(), 3, 4, 4);
        // 组装参数
        JSONObject json = new JSONObject();
        json.put("username", user.getUsername());
        json.put("status", user.getStatus());
        json.put("mobile", mobile);
        json.put("fax", user.getFax());
        json.put("orgName", orgBase.getOrgName());
        json.put("area", orgBase.getOrgAddr());

        return Result.succ("登录成功！", json);
    }

    @ApiOperation("机构信息验证 ")
    @PostMapping("valid")
    public Result valid(@Valid @RequestBody RegisterDTO orgUser, BindingResult result) throws Exception {

        Result res = Commonts.getErrors(result);
        if (!(null == res || "".equals(res))) {
            //return校验错误
            return Commonts.getErrors(result);
        }
        JSONObject data = new JSONObject();
        //校验企业基本信息
        OrgBase org = orgUser.orgInit();
        //查询校验机构信息
        String orgId = org.getOrgId();
        OrgBase base = new OrgBase();
        base.setOrgId(orgId);
        OrgBase orgBase = orgBaseService.selectOne(base);
        if (null == orgBase) {
            return Result.fail("无此机构信息");
        }
        if (!orgBase.getOrgName().equals(org.getOrgName()) || null == orgBase.getOrgName()) {
            return Result.fail("机构名不一致");
        }
        if (!orgBase.getLegalName().equals(org.getLegalName()) || null == orgBase.getLegalName()) {
            return Result.fail("法人姓名不一致");
        }
        if (!orgBase.getLegalIdcard().equals(org.getLegalIdcard()) || null == orgBase.getLegalIdcard()) {
            return Result.fail("法人证件号码不一致");
        }
        if (!orgBase.getOrgAddr().equals(org.getOrgAddr()) || null == orgBase.getOrgAddr()) {
            return Result.fail("注册地址不一致");
        }

        //回显mobile
        String mobile = orgBaseService.selectMobileByOrgId(orgId);

        data.put("orgId", orgBase.getOrgId());
        data.put("orgName", orgBase.getOrgName());
        data.put("legalName", orgBase.getLegalName());
        data.put("legalIdcard", orgBase.getLegalIdcard());
        data.put("orgAddr", orgBase.getOrgAddr());
        data.put("mobile", mobile);
        return Result.succ(data);
    }

    @ApiOperation("注册用户信息前验证")
    @PostMapping("registerValid")
    public Result registerValid(@Valid @RequestBody RegisterDTO orgUser, BindingResult result) throws Exception {

        //1、参数校验
        Result res = Commonts.getErrors(result);
        if (!(null == res || "".equals(res))) {
            //return校验错误
            return Commonts.getErrors(result);
        }

        //2、参数组装
        //初始化user
        User user = orgUser.userInit();
        if (null != orgUser.getUsername() && !"".equals(orgUser.getUsername())) {
            user.setId(CommonUtils.getUUID().toUpperCase())
                    .setPassword(CommonUtils.encodeByMd5(orgUser.getPassword()));
        }
        //初始化orgBase
        OrgBase orgBase = orgUser.orgInit();
        orgBase.setOrgId(orgUser.getOrgId());
        orgBase.setOrgFileName(orgUser.getOrgFileName());
        orgBase.setOrgFilePath(orgUser.getOrgFilePath());

        //3、查询验证
        res = userService.register(user, orgBase);
        return res;
    }


    @ApiOperation("验证通过，COMMIT注册新用户 ")
    @PostMapping("register")
    public Result register(@RequestBody RegisterDTO orgUser) throws Exception {

        OrgBase orgBase = orgUser.orgInit();
        orgBaseService.updateOrg(orgBase); //插入企业对应基本信息
        User user = orgUser.userInit();
        if (null != orgUser.getUsername() && !"".equals(orgUser.getUsername())) {
            user.setId(CommonUtils.getUUID().toUpperCase())
                    .setPassword(orgUser.getPassword());
        }
        userService.insertUser(user);//插入用户
        return Result.succ("注册成功");
    }

    @ApiOperation("找回用户名 ")
    @PostMapping("getUsername")
    public Result getUsername(@RequestBody RegisterDTO orgUser) {

        // 1、参数校验
        String orgId = orgUser.getOrgId();
        if (null == orgId || "".equals(orgId)) {
            log.error("社会统一信用代码为空");
            return Result.fail("社会统一信用代码不能为空");
        }

        // 2、获取用户名
        JSONObject data = new JSONObject();
        Map<Object, Object> map = new HashMap<>();

        String mobile = orgBaseService.selectMobileByOrgId(orgId);
        data.put("mobile", mobile);
        map.put("mobile", mobile);
        List<User> users = userService.selectListByMap(map);
        String username = users.get(0).getUsername();
        data.put("username", username);
        return Result.succ("用户名一经注册不能更改", data);

    }

    @ApiOperation("修改密码 ")
    @PutMapping("updatePassword")
    public Result updatePassword(@RequestBody User user) throws Exception {

        // 参数校验
        if (null == user.getUsername()) {
            Result.fail("用户名为空");
        }
        if (null == user.getPassword()) {
            Result.fail("新密码为空");
        }

        // 重置密码
        User newPassword = new User();
        newPassword.setUsername(user.getUsername());
        newPassword.setPassword(CommonUtils.encodeByMd5(user.getPassword()));// MD5加密

        // 入库，根据用户名修改密码
        userService.updateUser(newPassword);
        return Result.succ("修改密码成功");
    }

    @ApiOperation("修改手机号，信息备份 ")
    @PostMapping("updateMobile")
    public Result updateMobile(@Valid @RequestBody DataBak dataBak, BindingResult result) {

        // 1、校验参数
        Result res = Commonts.getErrors(result);
        if (!(null == res || "".equals(res))) {
            //return校验错误
            return Commonts.getErrors(result);
        }

        OrgBase orgBase = null;
        DataBak resData = null;
        try {
            // 查询新手机号是否被暂用
            orgBase = orgBaseService.selectOne(new OrgBase().setMobile(dataBak.getBakMobile()));
            // 通过orgId和审核状态(审核中)查询该企业是否重复提交
            DataBak newData = new DataBak();
            newData.setBakId(dataBak.getBakId()).setStatus(WAITTING);// 1-待审核
            resData = dataBakService.query(newData);
        } catch (Exception e) {
            log.info("新手机号无占用");
            log.info("新手机号无未提交过");
        }

        if (null != orgBase) {
            log.error("手机号已被使用");
            return Result.fail("手机号已被使用！");
        }

        if (null != resData) {
            log.error("该企业已提交过修改申请，正在审核中");
            return Result.fail("该企业已提交过修改申请，正在审核中，请勿重复申请！");
        }

        // 2、入库
        dataBak.setStatus(WAITTING); // 设置为1-待审核状态
        dataBakService.insert(dataBak);
        return Result.succ("修改手机号提交成功");
    }

    @ApiOperation("通过orgId获取手机号返显")
    @GetMapping("queryMobileByOrgId")
    public Result queryMobileByOrgId(@RequestParam String orgId) {

        String mobile = orgBaseService.selectMobileByOrgId(orgId);
        if (mobile == null) {
            return Result.fail(201, "请输入正确的统一信用代码", "手机号码");
        }
        return Result.succ("获取手机号成功", FuzzyUtil.cardFuzzy(mobile, 3, 4, 4));
    }

    @ApiOperation("通过username获取手机号返显")
    @GetMapping("queryMobileByUsername")
    public Result queryMobileByUsername(@RequestParam String username) {

        // 未输入
        if ("".equals(username) || null == username) {
            return Result.fail(201, "请输入用户名", "手机号码");
        }
        // 根据用户名查询手机号
        String mobile = null;
        try {
            mobile = userService.selectOne(new User().setUsername(username)).getMobile();
        } catch (Exception e) { // 不存在，给出错误信息
            return Result.fail(201, "用户名不存在", "手机号码");
        }
        // 存在，进行脱敏处理
        return Result.succ("获取手机号成功", FuzzyUtil.cardFuzzy(mobile, 3, 4, 4));
    }

    @ApiOperation("注销账户")
    @GetMapping("logout")
    public Map<String, Object> logout(HttpServletRequest request) {

        SecurityUtils.getSubject().logout();

        //System.out.println("logout: ");
        HttpSession session = (HttpSession) request.getAttribute("session");
        //System.out.println(session.getId());
        Map<String, Object> map = new HashMap<>();
        if (session.getAttribute("admin") != null) {
            request.removeAttribute("admin");
            map.put("code", 0);
            map.put("msg", "ok");
            map.put("data", 0);
        } else {
            map.put("code", 0);
            map.put("msg", "not login or timeout");
            map.put("data", 1);
        }
        //request.getSession().invalidate();//使当前session无效
        return map;
    }

    @ApiIgnore
    @DeleteMapping("delete")
    public void delete(@RequestBody User user) {
        //参数校验
        userService.deleteUser(null);
    }

}
